
import React, { Component } from 'react';

import {
    View,
    Image,
    ScrollView,
    Dimensions,
    Animated,
    TouchableOpacity,
    Platform
} from 'react-native';
import { BLACK_COLOR, WHITE_COLOR } from './config';
import UIImage from '../../../app/components/UIComponents/UIImage';

const IS_TAB_STYLE = Platform.OS === 'ios'?true:false
const {width,height}=Dimensions.get('window');

class UIBannerView extends Component{
    constructor(props){
        super();
        this.initState(props);
    }

    //初始化state的值
    initState = (props)=>{
        let currentPage = props.currentPage ? props.currentPage : 0
        const widthv = ( props.builtinWH && props.builtinWH.width ) ? props.builtinWH.width : width
        // const heightv = ( this.props.builtinWH && this.props.style.builtinWH.height) ? this.props.builtinWH.height : height
        const defaultBeginDrag = widthv * (currentPage + props.ifOffCircle ? 0 : 2)
        this.state = {
            //当前滚动到哪一页
            currentPage : currentPage,
            pointIndex : currentPage,
            //整数形式的currentPage
            intCP: -1,
            //总共有几页
            pageNum: props.imageArr.length,
            //记录当前是否为手指拖拽
            ifTouch: false,
            // 当onScroll水平滚动时的滚动大小(x值)的数组
            scrollXArr:[],
            // 当onScroll垂直滚动时的滚动大小(x值)的数组
            scrollYArr:[],
            //记录开始拖拽的位置
            beginDrag : { x : defaultBeginDrag },
            
            moveEventAnimated : new Animated.Value( defaultBeginDrag ),//默认应该是
            //ScrollView自身View的宽高
            viewHeight: props.style ? props.style.height : 0,
            viewWidth: props.style ? props.style.width : 0,

            //记录是否是首次
            ifFirst:true,
            //记录延迟执行循环轮播是否进行中
            loopStatus : false,
            //是否开启无限循环
            ifOffCircle : props.ifOffCircle ? true : false,
            //是否自动轮播
            ifAutoScroll : props.ifAutoScroll,
            width:  ( props.style && props.style.width ) ? props.style.width : width,
            height:  ( props.style && props.style.height) ? props.style.height : height,
            Mount: false,
        };
    };

    static defaultProps={
       
        //使用内置样式时用户自定义的图片宽高
        builtinWH:{
            width : width,
            height : height
        },

        //设置整个组件View的style样式
        style:{},

        //轮播图片的数组(该数组存在时使用该数组)
        imageArr:[],
        //如果是传入图片数组时,自定义的图片样式(该属性在自定义View时无用)
        imageStyle : null,
        //图片缩放
        imageScale : [1,0.8],
        //水平还是竖直方向的ScrollView
        HorV : 'h',
        //是否关闭无限循环
        ifOffCircle : false,
        //是否自动轮播
        ifAutoScroll : true,
        //自动轮播每张切换的时长(毫秒)
        infiniteInterval : 3000,
        //图片的显示形式
        resizeMode : 'cover',
        //点击图片时执行的操作(不是自定义View的时候)
        dealWithClickImage : null,
        //在当前滚动到的页面改变时调用的方法
        currentPageChangeFunc : null,
        //是否显示当前图片指示器View(下面的点)
        ifShowPointerView : true,
        //自定义指示器View的样式(绝对定位的top,bottom...)
        pointerViewStyle:null,
        //自定义指示器圆点的样式(圆点大小)
        pointerStyle:null,
        //指示器的两种颜色状态
        pointerColorArr : [ WHITE_COLOR, BLACK_COLOR ],
        //指示器的透明额度
        pointerOpacityArr : [ 1, 0.2 ],
        
    };
    UNSAFE_componentWillReceiveProps(nextProps){
        const pageNum = Array.isArray(nextProps.imageArr) ? nextProps.imageArr.length : 0
        
        if (pageNum != this.state.pageNum) {

            this.state.currentPage = 0
            this.state.pointIndex = 0
            this.state.pageNum = pageNum
            this.scrollToPage(this.state.currentPage,false)
        }

    }
    render() {

        if ( Array.isArray(this.props.imageArr) && this.props.imageArr.length ) {
            const { pageNum, currentPage, pointIndex } = this.state
            let { style, builtinWH } = this.props;
            return (
                <View style = { [ style || { flex : 1 } ] } onLayout = { this.viewOnLayout }>
                    
                    <ScrollView
                        // 设置引用名称,让下面可以引用到
                        ref = {(ps)=>{ this.scrollView = ps; }}
                        contentContainerStyle = {{ paddingHorizontal : ((this.state.width - builtinWH.width) / 2), minWidth : this.state.ifOffCircle ? this.state.pageNum * builtinWH.width : builtinWH.width * 5 }}
                        style = { { flex : 1 } }
                        decelerationRate = { 0 }
                        snapToAlignment = { 'start' }
                        snapToInterval = { this.state.ifOffCircle ? 0 : builtinWH.width }
                        contentOffset = { { x : builtinWH.width * ( this.state.currentPage + (this.state.ifOffCircle ? 0: 2) ) } }
                        scrollEnabled = { this.props.scrollEnabled }
                        // 是否是水平的scrollView(默认为水平方向的)
                        horizontal = { this.props.HorV === 'h' }
                        // 是否显示水平方向的滚动条
                        showsHorizontalScrollIndicator = { false }
                        // 是否显示竖方向的滚动条
                        showsVerticalScrollIndicator = { false }
                        // 开始拖拽
                        onScrollBeginDrag = { this.onScrollBeginDrag.bind(this) }
                        // 停止拖拽
                        onScrollEndDrag = { this.onScrollEndDrag.bind(this) }
                        onScroll = { ( e )=>this.onScroll( e ) }
                        onTouchStart = { this.onTouchStart.bind(this) }

                        //多少毫秒触发一次上面的onScroll方法
                        scrollEventThrottle = { 1 }
                        onLayout = { this.scrollViewOnLayout }
                    >
                        { this.renderScrollView.call(this) }
                    </ScrollView>
                    { this.props.ifShowPointerView ? 
                        <UIPointView 
                            ref = {ref => this.refs_UIPointView = ref} 
                            pointCount = { pageNum } 
                            selected = { pointIndex } 
                            pointerStyle = { this.props.pointerStyle }
                            pointerViewStyle = { this.props.pointerViewStyle }
                            pointerColorArr = { this.props.pointerColorArr }
                            pointerOpacityArr = { this.props.pointerOpacityArr }
                            /> : null }
                </View>
            );
        }
        return null
        
    }

    //view加载好之后
    viewOnLayout=()=>{
    //   console.log("viewOnLayout")
    };

    // 渲染scrollView
    renderScrollView=()=>{

        let { imageArr } = this.props;
        const { pageNum } = this.state;
        //datas数据
        let datas = imageArr.length ? imageArr : [];

        let arr = [];            
        let index = 0
        if (this.state.ifOffCircle) {
            //关闭无限循环
            for (let index = 0; index < pageNum; index++) {
                
                arr.push(<ImageViewItem 
                    key = { index } 
                    index = { index }
                    dataIndex = { index }
                    imageScale = { this.props.imageScale }
                    heightScale = { this.props.heightScale }
                    moveEventAnimated = { this.state.moveEventAnimated }
                    resizeMode = { this.props.resizeMode }
                    style = { this.props.builtinWH } 
                    imageStyle = { this.props.imageStyle } 
                    source = { datas[index] } 
                    onPress = { this.props.dealWithClickImage.bind(this) }/>)
            }
        }else{
            //两边需要预留出两个，作为可视假象
            for(let i = 0; i < (pageNum + 4); i++){
                let count = 0
                if ( i <= 1 || i >= (pageNum + 2)) {
                    if (pageNum > 1) {
                        if (i <= 1) {
                            count = pageNum - (2-i)
                        }else if (i >= (pageNum + 2) ) {
                            count =  i - (pageNum + 2)
                        }
                    } 
                }else{
                    count = index
                }
                arr.push(<ImageViewItem 
                        key = { i } 
                        index = { i }
                        dataIndex = { count }
                        imageScale = { this.props.imageScale }
                        heightScale = { this.props.heightScale }
                        moveEventAnimated = { this.state.moveEventAnimated }
                        resizeMode = { this.props.resizeMode }
                        style = { this.props.builtinWH } 
                        imageStyle = { this.props.imageStyle } 
                        source = { datas[count] } 
                        onPress = { this.props.dealWithClickImage.bind(this) }/>)
                if (i > 1 && i < (pageNum + 2)) {
                    index++
                }
            }
        }
        
        this.setInfiniteInterval()
        return arr
    };
    componentDidMount(){
        this.state.Mount = true;
    }
    componentWillUnmount(){
        this.state.Mount = false;
    }
    // 当滚动scrollView的时候(升级后)
    onScroll=(e)=>{
        // console.log(e.nativeEvent.contentOffset.x)
        if ( this.state && this.state.Mount ) {
            /**
             * 声明一个animated对象，每个ImageViewItem都监听这同一个animated。并根据offsize.x区间分割，映射到每一个ImageViewItem的可操作范围
             */
            if(this.props.HorV == 'h'){

                Animated.event(
                    [ { nativeEvent : { contentOffset : { x : this.state.moveEventAnimated } } } ],
                    { useNativeDriver : false }
                ).call(this,e)
            } else {

            }
        }
        
      
    };
   
    //scrollView加载好后,自身的尺寸
    scrollViewOnLayout=(event)=>{
        // console.log("scrollViewOnLayout")
          //若安卓不支持contentOffset初始设置，则需要这里进行兼容设置
       if (this.state.ifFirst && !IS_TAB_STYLE ) {
            this.state.ifFirst = false
           this.scrollToPage(this.state.currentPage,false)     
       }

    };
    //触目到scrollview
    onTouchStart = (e)=>{

        //循环，定位到安全区
        if ( this.state.loopStatus ) {
            //直接定位到位置，不用动画
            !this.state.ifOffCircle && this.scrollToPage.call(this,this.state.currentPage,false)
            this.state.loopStatus = false
        }
        
    }
    
   //开始拖拽
    onScrollBeginDrag=(e)=>{

        this.stopInfiniteInterval();
        if (this.state.ifTouch == false ) {
            //记录其实位置
            this.state.ifTouch=true;
        }

    };

    // 停止拖拽(移动距离是当前窗口的1/4)
    onScrollEndDrag=(e)=>{
        if (this.state.ifTouch) {
            let count = 0
            this.state.ifTouch=false;
            if (this.state.beginDrag) {
                let move = e.nativeEvent.contentOffset.x - this.state.beginDrag.x;
                if (move > 0) {
                    //向左
                    if (move > 30) {
                        count = 1;
                    }
                }else{
                    //向右
                    if (move < -30) {
                        count = -1;
                    }
    
                }
            }

            if (count != 0) {
                //处理循环反向操作
                if (this.state.loopStatus) {
                    count = -count
                }

                this.state.currentPage += count;
            }

            this.scrollToPage(this.state.currentPage,true)
        }
        this.setInfiniteInterval()

    };
  
    //根据传入的要滚动到的页面数,滚动到相应的页面
    scrollToPage=(currentPage,animated = true)=>{
        /**
         * 最少ImageArr 元素为1个，最多N个
         * 两边个预留两个视觉图，因此最少需要ImageViewItem为N+4个
         * 
         * 当滚动到第二个时需要无动画定位到ImageViewItem index 3 位置，
         * 当滚动到倒数第二个位置则，定位到ImageViewItem index (N+4)-3 位置
         * 
         * 每个ImageViewItem的宽度和高度是固定的，两边有固定的padding的值（(this.state.width - builtinWH.width)/2）
         * 当前滚动到的index = (e.nativeEvent.contentOffset.x - （(this.state.width - builtinWH.width)/2）) / builtinWH.width
         */
        /**
         *  （ -2 < currentPage < this.pageNum+2 ）
         * -1 的时候替换成 this.pageNum -1 
         * thi.pageNum+1 的时候替换成 0
         * 
         */
        let oldPointIndex = this.state.pointIndex;
        
        if( currentPage >= this.state.pageNum  ){
            this.state.pointIndex = this.state.ifOffCircle ? this.state.pageNum -1 : 0
            this.state.loopStatus =  true
        } else if( currentPage < 0 ){
            this.state.pointIndex = this.state.ifOffCircle ? 0 : this.state.pageNum - 1
            this.state.loopStatus = true
        } else {
            this.state.pointIndex = currentPage
            this.state.loopStatus = false
        }
        
        if( this.state.loopStatus && (!animated || this.state.ifOffCircle ) ){
            //需要循环，且不需要动画过渡
            currentPage = this.state.pointIndex
        }
       
        //动画过渡
        this.setScrollTo.call(this, currentPage, animated)
            
        //定位Pointer 优化，不能总是渲染会增加内存增长
        this.refs_UIPointView && this.refs_UIPointView.setSlected(this.state.pointIndex)
        if (oldPointIndex != this.state.pointIndex) {
            this.props.currentPageChangeFunc && this.props.currentPageChangeFunc(this.state.pointIndex)
        }
       
        
    };

    //定位到指定位置
    setScrollTo(currentPage, animated){

        if (this.state.currentPage != currentPage) {
            this.setState({
                pointIndex:currentPage,
                currentPage:currentPage
            })
        }
        try{
            if (this.props.HorV == 'h') {
                let x =  this.state.ifOffCircle ? currentPage * this.props.builtinWH.width : ((currentPage + 2) * this.props.builtinWH.width)  
                this.state.beginDrag['x'] = x;
                this.scrollView.scrollTo({x : x, animated: animated})
    
            }
        }catch (e){
            
        }
       
    }

    //设置轮播的定时器
    setInfiniteInterval = ()=>{
        this.state.timer && this.stopInfiniteInterval()

        if (this.state.ifAutoScroll && Array.isArray(this.props.imageArr) && this.props.imageArr.length > 1) {

            let interval = this.props.infiniteInterval < 1000 ? 1000 : this.props.infiniteInterval;
            this.state.timer = setInterval(()=>{
                if ( !this.state.ifTouch ) {

                    //循环，定位到安全区
                    if ( this.state.loopStatus ) {
                     
                        this.scrollToPage( this.state.currentPage, false)
                    }
                    this.state.currentPage += 1
                    this.scrollToPage( Math.round( this.state.currentPage ),true);
                }
            },interval)
        }
       
    };

    //清除轮播定时器
    stopInfiniteInterval=()=>{
        
        if (this.state.timer) {
            clearInterval(this.state.timer);
            this.state.timer = null
        }
    }

    componentWillUnmount(){

        this.stopInfiniteInterval();

    }

}

class ImageViewItem extends Component{
    constructor(props,content){
        super(props,content)
        this.state = {
            source : props.source,
            moveEventAnimated : props.moveEventAnimated ? props.moveEventAnimated : new Animated.Value(-1),
        }

    }
  
    render(){
        const {
            source,
        } = this.props
        const {
            width : widthv,
            height : heightv
        } = this.props.style
        
        return(
            <TouchableOpacity 
                style = {[{
                    // flex : 1,
                    // backgroundColor : GREEN_BACK_COLOR,
                },]}
                activeOpacity={this.props.onPress ?  0.8 : 1} 
                onPress={()=>{
                    this.props.onPress && this.props.onPress(this.props.dataIndex)
                }}>
                <View style = {{ width : '100%', height : '100%', justifyContent : 'center', alignItems:'center',}} >

                    <Animated.View style={[
                        this.props.imageStyle,
                        
                        {transform : [
                            { scale : this.state.moveEventAnimated.interpolate({
                                inputRange : [ widthv * (this.props.index - 1), widthv * (this.props.index - 1) + 5,  widthv * this.props.index, widthv * (this.props.index + 1 ) - 5, widthv * (this.props.index + 1 ) ],
                                outputRange : [ this.props.imageScale[1], this.props.imageScale[1], this.props.imageScale[0], this.props.imageScale[1], this.props.imageScale[1] ]
                            })}
                        ]},
                        this.props.heightScale ? {
                            height :  this.state.moveEventAnimated.interpolate({
                                inputRange : [ widthv * (this.props.index - 1), widthv * (this.props.index - 1) + 5,  widthv * this.props.index, widthv * (this.props.index + 1 ) - 5, widthv * (this.props.index + 1 ) ],
                                outputRange : [ this.props.heightScale * heightv, this.props.heightScale * heightv, 1 * heightv,this.props.heightScale * heightv, this.props.heightScale * heightv ]
                            })
                        } : null]}>
                            <Animated.View style = {[{
                                    overflow : 'hidden', 
                                    borderRadius : this.props.imageStyle && this.props.imageStyle.borderRadius ? this.props.imageStyle.borderRadius : 0,
                                },
                                this.props.heightScale ? {
                                    height : this.state.moveEventAnimated.interpolate({
                                        inputRange : [ widthv * (this.props.index - 1), widthv * (this.props.index - 1) + 5,  widthv * this.props.index, widthv * (this.props.index + 1 ) - 5, widthv * (this.props.index + 1 ) ],
                                        outputRange : [ this.props.heightScale * heightv, this.props.heightScale * heightv, 1 * heightv,this.props.heightScale * heightv, this.props.heightScale * heightv ]
                                    })
                                } : null
                                ]}>
                                <UIImage 
                                    source = { source } 
                                    resizeMode = { this.props.resizeMode }
                                    style = {[
                                    { 
                                        width :'100%',
                                        height : '100%',
                                        borderRadius : this.props.imageStyle && this.props.imageStyle.borderRadius ? this.props.imageStyle.borderRadius : 0,
                                    },
                                    this.props.imageStyle,
                                    // {transform : [
                                    //     { scale : this.state.moveEventAnimated.interpolate({
                                    //         inputRange : [ widthv * (this.props.index - 1), widthv * (this.props.index - 1) + 5,  widthv * this.props.index, widthv * (this.props.index + 1 ) - 5, widthv * (this.props.index + 1 ) ],
                                    //         outputRange : [ this.props.imageScale[1], this.props.imageScale[1], this.props.imageScale[0], this.props.imageScale[1], this.props.imageScale[1] ]
                                    //     })}
                                    // ]},
                                    // this.props.heightScale ? {
                                    //     height :  this.state.moveEventAnimated.interpolate({
                                    //         inputRange : [ widthv * (this.props.index - 1), widthv * (this.props.index - 1) + 5,  widthv * this.props.index, widthv * (this.props.index + 1 ) - 5, widthv * (this.props.index + 1 ) ],
                                    //         outputRange : [ this.props.heightScale * heightv, this.props.heightScale * heightv, 1 * heightv,this.props.heightScale * heightv, this.props.heightScale * heightv ]
                                    //     })
                                    // } : null
                                    ]}>
                                </UIImage>
                            </Animated.View>
                            
                    </Animated.View>
                </View>
                 
            </TouchableOpacity>
        )
    }
}

class UIPointView extends Component{
    constructor(props){
        super()
        
        let pointCount = props.pointCount ? props.pointCount : 1
        this.refs_pointViewArray = {};
        this.state = {
            pointCount : pointCount,
            selected : props.selected ? props.selected : 0,
            pointArray : null,//避免每次render函数创造多次point，pointCount不变的情况下不需要render
        }

    }
    render(){

        return(
            <View style = { [ { position : 'absolute', bottom : 10, flexDirection : 'row',alignSelf :"center", justifyContent : 'center', }, this.props.pointerViewStyle ]}>
                { this.renderPointer(this.state.pointCount, this.state.selected) }
            </View>
        )
    }
    UNSAFE_componentWillReceiveProps( nextProps ){
        //这里直接给pointArray 赋值因为shouldComponentsUpdate可以通过setState触发，但是真正的给this.state.pointArray赋值需要等shouldComponentsUpdate：return true
        // this.state.pointArray = nextProps.pointCount != this.state.pointCount ? null : this.state.pointArray;
        this.setState({
            pointCount : nextProps.pointCount,
            selected : nextProps.selected,
            pointArray : nextProps.pointCount != this.state.pointCount ? null : this.state.pointArray
        })

    }
    //赋值需要等return true,fales 不会改变属性
    shouldComponentUpdate(nextProps, nextState){
        
        //优化性能
        if (nextState.selected != this.state.selected) {

            if (Array.isArray(nextState.pointArray) && Array.isArray(this.state.pointArray) && this.state.pointArray.length > nextState.selected && nextState.selected >= 0) {

                //已选中的更改为未选
                let pointVO = this.refs_pointViewArray[`pointView${this.state.selected}`]
                pointVO && pointVO.setState({
                    selected : nextState.selected
                })
                this.state.selected = nextState.selected;
                //未选中的更改为已选中
                let pointVN = this.refs_pointViewArray[`pointView${this.state.selected}`]
                pointVN && pointVN.setState({
                    selected : nextState.selected
                })

            }else{

                this.state.selected = nextState.selected;
                return true
            }
        }

        if (this.state.pointCount != nextState.pointCount || nextState.pointArray != this.state.pointArray ) {

            return true
        }
            

        return false
    }
    setSlected( selected ){
        if ( selected != this.state.selected && Array.isArray(this.state.pointArray) && this.state.pointArray.length > selected && selected >= 0 ) {
            
            this.setState({
                selected : selected,
            })
        }
       
    }
    renderPointer = ( pointCount, selected )=>{

        if ( !this.state.pointArray ) {

            let viewArr=[];
            for ( let i = 0; i < pointCount; i++ ){

                viewArr.push(
                    <UIPoint
                        ref = {ref => { this.refs_pointViewArray[`pointView${i}`] = ref} }
                        key = { i }
                        index = { i }
                        selected = { selected }
                        pointerStyle = { this.props.pointerStyle }
                        pointerColorArr = { this.props.pointerColorArr }
                        pointerOpacityArr = { this.props.pointerOpacityArr }
                        />);
            }

            this.state.pointArray = viewArr;
        }
       
        return this.state.pointArray
    };
}
class UIPoint extends Component{
    constructor( props ){
        super()
        this.state = {
            index : props.index,
            selected : props.selected,
        }
    }
    UNSAFE_componentWillReceiveProps( nextProps ){

        this.setState({
            index : nextProps.index,
            selected : nextProps.selected
        })
    }

    render(){

        return(
            <View 
                style = { [ 
                    { 
                        width : 8,
                        height : 8, 
                        borderRadius : 4, 
                        marginLeft : ( this.state.key == 0 ) ? 0 : 10
                        },
                        this.props.pointerStyle,
                        {
                        backgroundColor : ( this.state.index == this.state.selected ) ? this.props.pointerColorArr[0] : this.props.pointerColorArr[1],
                        opacity : ( this.state.index == this.state.selected )? this.props.pointerOpacityArr[0] : this.props.pointerOpacityArr[1],
                        }
                ]}/>
        )
    }
}
//输出组件类
export default UIBannerView;